package DSA_Proj;

import java.awt.Color;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

class GUI extends JFrame {
    private String dirName = "";
    private JProgressBar progressBar;
    private JTextArea outputArea;
    private JTextArea directoryPath;
    private StringBuffer stringRepeat = new StringBuffer();
    private long startTime;
    private long endTime;

    GUI() {
        setTitle("数据结构课程设计");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(600, 300, 651, 444);
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JLabel labelKMP = new JLabel("KMP算法求解最长公共子序列问题");
        labelKMP.setHorizontalAlignment(SwingConstants.CENTER);
        labelKMP.setFont(new Font("Microsoft YaHei Light", Font.BOLD, 20));
        labelKMP.setBounds(148, 10, 362, 61);
        contentPane.add(labelKMP);

        // 输出结果的控件
        outputArea = new JTextArea();
        JScrollPane scroll = new JScrollPane(outputArea);
        outputArea.setEditable(false);
        outputArea.setFont(new Font("宋体", Font.PLAIN, 20));
        scroll.setBounds(10, 246, 615, 149);
        contentPane.add(scroll);

        JLabel labelDirectory = new JLabel("目录路径:");
        labelDirectory.setFont(new Font("Microsoft YaHei UI Light", Font.PLAIN, 18));
        labelDirectory.setBounds(20, 81, 114, 39);
        contentPane.add(labelDirectory);

        directoryPath = new JTextArea();
        directoryPath.setEditable(false);
        directoryPath.setFont(new Font("Microsoft YaHei Light", Font.PLAIN, 18));
        directoryPath.setBounds(125, 81, 362, 35);
        contentPane.add(directoryPath);

        // 选择路径的按钮
        JButton chooseDirectory = new JButton("选择目录");
        chooseDirectory.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 12));
        chooseDirectory.addActionListener(e -> {
            stringRepeat = new StringBuffer();
            directoryPath.setText("");
            outputArea.setText("");
            progressBar.setValue(0);
            JFileChooser chooser = new JFileChooser();
            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            chooser.showOpenDialog(contentPane);
            if (chooser.getSelectedFile() != null) {
                directoryPath.setText(chooser.getSelectedFile().getPath());
                dirName = chooser.getSelectedFile().getPath();
            }
        });
        chooseDirectory.setBounds(511, 81, 114, 39);
        contentPane.add(chooseDirectory);

        // 进度条
        progressBar = new JProgressBar();
        progressBar.setStringPainted(true);
        progressBar.setBackground(new Color(255, 255, 255));
        progressBar.setBounds(125, 146, 362, 39);
        contentPane.add(progressBar);

        // 开始比较的按钮
        JButton startButton = new JButton("开始查找");
        startButton.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 12));
        startButton.addActionListener(e -> {
            if (dirName.equals("")) {
                JOptionPane.showMessageDialog(contentPane, "请选择目录", "Message", JOptionPane.INFORMATION_MESSAGE);
            } else {
                TextRepeat T = new TextRepeat();
                T.execute();
            }
        });
        startButton.setBounds(511, 147, 114, 39);
        contentPane.add(startButton);

        JLabel labelResult = new JLabel("  查找结果:");
        labelResult.setFont(new Font("Microsoft YaHei Light", Font.PLAIN, 18));
        labelResult.setBounds(10, 208, 114, 28);
        contentPane.add(labelResult);

        JLabel labelProgress = new JLabel("  查找进度:");
        labelProgress.setFont(new Font("Microsoft YaHei UI Light", Font.PLAIN, 18));
        labelProgress.setBounds(10, 146, 114, 39);
        contentPane.add(labelProgress);
    }

    private class TextRepeat extends SwingWorker<Void, Void> {
        private int index = 0;//结点数组索引
        private String directory;//目录
        private ArrayList<resultNode> results = new ArrayList<>();//结点数组，包含所有文件组合
        private double progress = 0.0;

        //设置目录，初始化结点数组（泽铭）
        void setDirectory(String dir) {
            directory = new File(dir).getAbsolutePath();
            String[] fileList = new File(dir).list();
            for (String fileNameA : fileList) {
                for (String fileNameB : fileList) {
                    if (!fileNameA.equals(fileNameB)) {
                        results.add(new resultNode(fileNameA, fileNameB, 0));//增加新结点
                    }
                }
            }
        }

        //将文件内容转为字符串并返回（宜高）
        private String getContent(File file) throws IOException {
            String content = "";
            InputStreamReader inStream = new InputStreamReader(new FileInputStream((file)));
            BufferedReader buffer = new BufferedReader(inStream);

            String line = buffer.readLine();
            while (line != null) {//逐行读取文件直至文件尾
                content = content + line;
                line = buffer.readLine();
            }

            inStream.close();
            buffer.close();
            return content;
        }

        //设置所有结点的重复度（泽铭）
        void calAllRepeat() {
            double count = 0;
            for (resultNode result : results) {//遍历结点数组
                count++;
                File fileA = new File(directory + File.separator + result.fileA);
                File fileB = new File(directory + File.separator + result.fileB);
                progress = count / results.size() * 100 / 1;
                progressBar.setValue((int) progress);
                try {
                    getRepeat(getContent(fileA), getContent(fileB));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //KMP算法（宇宏）
        private boolean KMPisContain(String main, String s) {
            int size = s.length();
            int[] next = new int[size + 1];

            next[1] = 0;
            if (size > 2)
                next[2] = 1;

            for (int i = 2; i < size; i++) {
                int p = i;
                outer:
                while (true) {
                    if (p > 1 && s.charAt(i - 1) == s.charAt(next[p] - 1)) {
                        next[i + 1] = next[p] + 1;
                        break outer;
                    } else if (p == 1) {
                        next[i + 1] = 1;
                        break outer;
                    } else {
                        p = next[p];
                    }
                }
            }
            int i = 0;
            int j = 0;
            while (j < size && i < main.length()) {
                if (main.charAt(i) == s.charAt(j)) {
                    ++i;
                    ++j;
                } else if (j == 0)
                    i++;
                else j = next[j];
            }

            return (j == size);
        }

        //计算两个文件的重复度（宇宏）
        private void getRepeat(String s1, String s2) {
            int repeat;
            StringBuffer maxSon = new StringBuffer();
            int Max, i = 0;
            int size1 = s1.length();
            int size2 = s2.length();
            if (size2 > size1) {
                end1:
                for (Max = 1; Max <= size1; Max++) {
                    for (; i + Max <= size1; i++) {
                        String son = s1.substring(i, i + Max);
                        if (KMPisContain(s2, son)) {
                            maxSon = new StringBuffer(son);
                            break;
                        }
                        if (i + Max == size1) {
                            break end1;
                        }
                    }
                    if (i + Max == size1) {
                        repeat = Max - 1;
                    }
                }
            } else {
                end2:
                for (Max = 1; Max <= size2; Max++) {
                    for (; i + Max <= size2; i++) {
                        String son = s2.substring(i, i + Max);
                        if (KMPisContain(s1, son)) {
                            maxSon = new StringBuffer(son);
                            break;
                        }
                        if (i + Max == size2)
                            break end2;
                    }
                }
            }
            if (maxSon.length() > stringRepeat.length())
                stringRepeat.append(maxSon);
            repeat = Max - 1;
            results.get(index++).setRepeat(repeat);
        }

        //遍历结点数组，返回最大重复度的结点（泽铭）
        resultNode getHighestRepeat() {
            resultNode r = new resultNode("", "", 0);
            for (resultNode result : results) {
                if (result.repeat > r.repeat) {
                    r.fileA = result.fileA;
                    r.fileB = result.fileB;
                    r.repeat = result.repeat;
                }
            }
            return r;
        }

        //SwingWorker后台线程
        @Override
        protected Void doInBackground() throws Exception {
            resultNode result;
            TextRepeat T = new TextRepeat();
            T.setDirectory(dirName);
            startTime = System.currentTimeMillis();
            T.calAllRepeat();
            endTime = System.currentTimeMillis();
            result = T.getHighestRepeat();

            outputArea.setText("拥有最长子序列的两个文档为: \"" + result.fileA + "\" 和 \"" + result.fileB + "\".\r\n"
                    + "重复度为: " + result.repeat + "用时:\r\n" + (endTime - startTime) + "(ms)\r\n" + "最长子序列为: \r\n" + stringRepeat + "\r\n"
            );

            return null;
        }
    }
}